////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
//  File name:   animsequence.h
//  Version:     v1.00
//  Created:     26/4/2002 by Timur.
//  Compilers:   Visual Studio.NET
//  Description: Implementation of IAnimSequence interface.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __animsequence_h__
#define __animsequence_h__

#if _MSC_VER > 1000
#pragma once
#endif

#include "IMovieSystem.h"

class CAnimSequence : public IAnimSequence
{
public:
	CAnimSequence( IMovieSystem *pMovieSystem, uint32 id );
	~CAnimSequence();

	//////////////////////////////////////////////////////////////////////////
	virtual void Release() { if (--m_nRefCounter <= 0) delete this; }
	//////////////////////////////////////////////////////////////////////////

	// Movie system.
	IMovieSystem* GetMovieSystem() const { return m_pMovieSystem; };

	const char* GetFullName() const;
	void SetName( const char *name );
	const char* GetName() const;
	uint32 GetId() const
	{ return m_id; }
	
	float GetFixedTimeStep() const
	{ return m_fixedTimeStep; }
	void SetFixedTimeStep(float dt)
	{ m_fixedTimeStep = dt; }

	IAnimSequenceGroup* GetGroup() const;
	void SetGroup(IAnimSequenceGroup *pGroup);
	void SetGroupAndName(IAnimSequenceGroup *pGroup, const char *name);

	VIRTUAL void SetOwner( IAnimSequenceOwner *pOwner )
	{ m_pOwner = pOwner; }
	VIRTUAL IAnimSequenceOwner* GetOwner() const
	{ return m_pOwner; }

	VIRTUAL void SetActiveDirector(IAnimNode *pDirectorNode);
	VIRTUAL IAnimNode *GetActiveDirector() const;

	VIRTUAL void SetFlags( int flags );
	VIRTUAL int GetFlags() const;
	VIRTUAL int GetCutSceneFlags(const bool localFlags = false) const;

	VIRTUAL void SetParentSequence(IAnimSequence *pParentSequence);
	VIRTUAL const IAnimSequence* GetParentSequence() const;
	VIRTUAL bool IsAncestorOf(const IAnimSequence *pSequence) const;

	void SetTimeRange( Range timeRange );
	Range GetTimeRange() { return m_timeRange; };

	void AdjustKeysToTimeRange( const Range &timeRange );

	//! Return number of animation nodes in sequence.
	int GetNodeCount() const;
	//! Get specified animation node.
	IAnimNode* GetNode( int index ) const;
	
	IAnimNode* FindNodeByName( const char *sNodeName );
	IAnimNode* FindNodeById( int nNodeId );
	VIRTUAL void ReorderNode( IAnimNode *node,IAnimNode *pPivotNode, bool next );

	void Reset( bool bSeekToStart );
	void ResetHard();
	void Pause();
	void Resume();

	//! Add animation node to sequence.
	bool AddNode( IAnimNode *node );
	IAnimNode* CreateNode( EAnimNodeType nodeType );
	void RemoveNode( IAnimNode *node );
	//! Add scene node to sequence.
	void RemoveAll();

	VIRTUAL void Activate();
	VIRTUAL void Deactivate();
	VIRTUAL void PrecacheData(float startTime = 0.0f);

	void StillUpdate();
	void Animate( SAnimContext &ec );
	void Render();

	void Serialize( XmlNodeRef &xmlNode,bool bLoading, bool bLoadEmptyTracks=true );
	void CopyNodes(XmlNodeRef& xmlNode, IAnimNode** pSelectedNodes, uint32 count);
	void PasteNodes(const XmlNodeRef& xmlNode, IAnimNode *pParent);

	//! Add/remove track events in sequence
	VIRTUAL bool AddTrackEvent(const char* szEvent);
	VIRTUAL bool RemoveTrackEvent(const char* szEvent);
	VIRTUAL bool RenameTrackEvent(const char* szEvent, const char* szNewEvent);
	VIRTUAL bool MoveUpTrackEvent(const char* szEvent);
	VIRTUAL bool MoveDownTrackEvent(const char* szEvent);
	VIRTUAL void ClearTrackEvents();

	//! Get the track events in the sequence
	VIRTUAL int GetTrackEventsCount() const;
	VIRTUAL char const* GetTrackEvent(int iIndex) const;

	//! Call to trigger a track event
	VIRTUAL void TriggerTrackEvent(const char* event, const char* param = NULL);

	//! Track event listener
	VIRTUAL void AddTrackEventListener(ITrackEventListener *pListener);
	VIRTUAL void RemoveTrackEventListener(ITrackEventListener *pListener);

	VIRTUAL void GetMemoryUsage( ICrySizer *pSizer ) const
	{
		pSizer->AddObject(this, sizeof(*this));
		pSizer->AddObject(m_name);
		pSizer->AddObject(m_nodes);
		pSizer->AddObject(m_listeners);
	}
private:
	void ComputeTimeRange();
	void CopyNodeChildren(XmlNodeRef& xmlNode, IAnimNode* pAnimNode);
	void NotifyTrackEvent(ITrackEventListener::EReason reason, 
												const char* event, const char* param = NULL);
	
	// Create a new animation node.
	IAnimNode* CreateNodeInternal( EAnimNodeType nodeType,uint32 nNodeId=-1 );

	bool AddNodeNeedToRender(IAnimNode* pNode);
	void RemoveNodeNeedToRender(IAnimNode* pNode);

	typedef std::vector< _smart_ptr<IAnimNode> > AnimNodes;
	AnimNodes m_nodes;
	AnimNodes m_nodesNeedToRender;

	uint32 m_id;
	string m_name;
	mutable string m_fullNameHolder;
	Range m_timeRange;
	TrackEvents m_events;

	// Listeners
	typedef std::list<ITrackEventListener*> TTrackEventListeners;
	TTrackEventListeners m_listeners;

	int m_flags;

	bool m_precached;
	bool m_resetting;

	IAnimSequence *m_pParentSequence;

	//
	IMovieSystem *m_pMovieSystem;
	bool m_bPaused;
	bool m_bActive;

	uint32 m_lastGenId;

	IAnimSequenceGroup* m_pGroup;
	IAnimSequenceOwner* m_pOwner;

	IAnimNode *m_pActiveDirector;

	float m_fixedTimeStep;
};

#endif // __animsequence_h__
